<template>
	<view>
		<!-- #ifdef APP-NVUE -->
		<view @click="open">
			<view :eventPenetrationEnabled="true">
				<slot name="trigger"></slot>
			</view>
		</view>
		<!-- #endif -->
		<!-- #ifndef APP-NVUE -->
		<view @click="open">
			<slot name="trigger"></slot>
		</view>
		<!-- #endif -->

		<zh-overlay :inContent="props.inContent" ref="overlayAni" :duration="props.duration + 80" @open="OverLayOpen"
			@close="overclose" :zIndex="props.zIndex" :transprent="!props.mask" @click="overlayClickFun"
			:align="align_rp" :teleport="props.teleport" :overlayClick="false" v-model:show="_show">
			<zh-translate :reverse="reverse_rp" :width="anwidth" :height="anheight" ref="drawerANI" :auto-play="false"
				:name="aniname" :duration="props.duration+80" @end="playEndEvent">
				<view @click.stop="$event.stopPropagation()" :style="[
						{ width: anwidth, height: anheight },
						!props.transprent ? tmcomputed.borderCss : '',
						!props.transprent ? tmcomputed.backgroundColorCss : '',
						!props.transprent ? tmcomputed.shadowColor : '',
						customCSSStyle
					]" :class="[round_rp, 'flex flex-col overflow ', customClass]">

					<view v-if="!props.closeable && !props.hideHeader"
						class="flex flex-row flex-row-center-center flex-between px-24" style="height: 44px">
						<view class="flex-4 flex-shrink">
							<zh-text v-if="!props.hideCancel && !loading && !ok_loading" @click="cancel"
								:label="props.cancelText"></zh-text>
						</view>
						<view class="flex-8 px-32 flex-center">
							<slot name="title"><zh-text _class="text-overflow-1 opacity-7"
									:label="props.title"></zh-text></slot>
						</view>
						<view class="flex-4 flex-shrink flex-row flex-row-center-end">
							<zh-text :color="okColor" @click="ok" v-if="!ok_loading && !loading" :dark="props.dark"
								:label="props.okText"></zh-text>
							<tm-icon :color="okColor" v-if="ok_loading || loading" :spin="ok_loading || loading"
								:dark="isDark" :_class="isDark !== true ? 'opacity-4' : ''" :fontSize="24"
								:name="ok_loading || loading ? 'tmicon-shuaxin' : 'tmicon-times-circle-fill'"></tm-icon>
						</view>
					</view>
					<view v-if="props.closeable && !props.hideHeader"
						class="flex flex-row flex-row-center-center flex-between px-24" style="height: 44px">
						<view class="flex-9 pr-32">
							<slot name="title"><zh-text _class="text-overflow-1 opacity-7" :dark="props.dark"
									:label="props.title"></zh-text></slot>
						</view>
						<view class="flex-3 flex-shrink flex-row flex-row-center-end">
							<tm-icon @click="cancel" :dark="props.dark" :_class="isDark !== true ? 'opacity-3' : ''"
								:fontSize="36" name="tmicon-times-circle-fill"></tm-icon>
						</view>
					</view>
					<!-- #ifdef APP-NVUE -->
					<scroll-view :scroll-y="!props.disabbleScroll" :style="[{ height: contentHeight }]"
						class="overflow">
						<slot name="default"></slot>
					</scroll-view>
					<!-- #endif -->
					<!-- #ifndef APP-NVUE -->
					<view :style="{
							overflowY: props.disabbleScroll ? 'normal' : 'auto',
							height: contentHeight
						}">
						<slot name="default"></slot>
					</view>
					<!-- #endif -->
					<slot name="foot">
						<view v-if="props.footHeight > 0" class="flex"></view>
					</slot>
				</view>
			</zh-translate>
		</zh-overlay>
	</view>
</template>

<script lang="ts" setup>
	/**
 * 抽屉
 * @description 别名poup弹层，提供，左，右，上，下，中弹出内容。
 */
	import { getCurrentInstance, computed, ref, provide, inject, onMounted, onUnmounted, nextTick, watch } from 'vue'
	import { cssstyle, colorThemeType } from '@/tool/lib/interface'
	import { custom_props, computedTheme, computedClass, computedStyle, computedDark } from '@/tool/lib/minxs'
	import { useWindowInfo } from '@/tool/useFun/useWindowInfo'
	import systemConfigStore from '@/store/modules/systemConfigStore';
	const store = systemConfigStore();
	const drawerANI = ref<any>(null)
	const overlayAni = ref<any>(null)

	const props = defineProps({
		...custom_props,
		//是否显示遮罩
		mask: {
			type: [Boolean, String],
			default: true
		},
		//抽屉放置的位置
		placement: {
			type: String,
			default: 'bottom' //top|left|right|bottom|center
		},
		show: {
			type: [Boolean],
			default: false
		},
		width: {
			type: Number,
			default: 500
		},
		height: {
			type: Number,
			default: 600
		},
		round: {
			type: Number,
			default: 10
		},
		//弹出的动画时间单位ms.
		duration: {
			type: Number,
			default: 300
		},
		//是否允许点击遮罩关闭
		overlayClick: {
			type: Boolean,
			default: true
		},
		transprent: {
			type: [Boolean, String],
			default: false
		},
		//如果显示关闭。标题栏被替换为左标题右关闭按钮。
		closeable: {
			type: [Boolean, String],
			default: false
		},
		color: {
			type: String,
			default: 'white'
		},
		title: [String],
		okText: {
			type: [String],
			default: '完成'
		},
		okColor: {
			type: [String],
			default: 'primary'
		},
		//true时，确认按钮将出现加载状态。
		okLoading: {
			type: [Boolean, String],
			default: false
		},
		cancelText: {
			type: [String],
			default: '取消'
		},
		hideCancel: {
			type: [Boolean, String],
			default: false
		},
		//隐藏工具栏，标题，取消，确认
		hideHeader: {
			type: [Boolean, String],
			default: false
		},
		disabled: {
			type: Boolean,
			default: false
		},
		zIndex: {
			type: [Number, String],
			default: 401
		},
		unit: {
			type: String,
			default: 'rpx'
		},
		disabbleScroll: {
			type: Boolean,
			default: false
		},
		/** 是否嵌入弹层，开启后将在它的父组件内执行弹层。 */
		inContent: {
			type: Boolean,
			default: false
		},
		footHeight: {
			type: Number,
			default: 0
		},
		/** 是否使用teleport */
		teleport: {
			type: Boolean,
			default: true
		},
		/**打开前执行 */
		beforeOpen: {
			type: Function,
			default: null
		},
		/**关点击ok前执行，如果返回是false，将阻止关闭. */
		beforeOk: {
			type: Function,
			default: null
		},
		/**点击取消前执行，如果返回fase将阻止关闭. */
		beforeCance: {
			type: Function,
			default: null
		}
	})
	const emits = defineEmits(['click', 'open', 'close', 'update:show', 'ok', 'cancel'])
	const proxy = getCurrentInstance()?.proxy ?? null
	const sysinfo = useWindowInfo();
	// 设置响应式全局组件库配置表。
	const tmcfg = computed<any>(() => store)
	//自定义样式：
	const customCSSStyle = computed(() => computedStyle(props))
	//自定类
	const customClass = computed(() => computedClass(props))
	//是否暗黑模式。
	const isDark = computed(() => computedDark(props, tmcfg.value))
	//计算主题
	const tmcomputed = computed<cssstyle>(() => computedTheme(props, isDark.value, tmcfg.value))

	const reverse = ref(true)
	const timeid = ref(0)
	let timerId : any = NaN
	let timerIdth : any = NaN
	let timerIdth_flas = false
	uni.hideKeyboard()
	let _show = ref(props.show)
	const isPlaying = ref(false)
	function debounce(func : Function, wait = 500, immediate = false) {
		// 清除定时器
		if (!isNaN(timerId)) clearTimeout(timerId)
		// 立即执行，此类情况一般用不到

		if (immediate) {
			timerId = setTimeout(() => {
				timerId = NaN
			}, wait)
			typeof func === 'function' && func()
		} else {
			// 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
			timerId = setTimeout(() => {
				typeof func === 'function' && func()
			}, wait)
		}
	}

	function throttle(func : Function, wait = 500, immediate = true) {
		if (immediate) {
			if (!timerIdth_flas) {
				timerIdth_flas = true
				// 如果是立即执行，则在wait毫秒内开始时执行
				typeof func === 'function' && func()

				timerIdth = setTimeout(() => {
					timerIdth_flas = false
				}, wait)
			}
		} else {
			if (!timerIdth_flas) {
				timerIdth_flas = true
				// 如果是非立即执行，则在wait毫秒内的结束处执行
				timerIdth = setTimeout(() => {
					timerIdth_flas = false
					typeof func === 'function' && func()
				}, wait)
			}
		}
	}

	timeid.value = uni.$tm.u.getUid(4)
	if (_show.value) {
		reverse.value = false
	}
	watch(
		() => props.show,
		(val) => {
			if (val) {
				reverse.value = true
			} else {
				reverse.value = false
				overlayAni.value?.close()
			}
			if (_show.value !== props.show) {
				nextTick(() => {
					drawerANI.value?.play()
					isPlaying.value = true;
				})
			}
			_show.value = props.show
		}
	)
	onMounted(() => {
		if (_show.value) {
			open()
		}
	})
	const ok_loading = computed(() => props.okLoading)
	const loading = ref(false)
	const round_rp = computed(() => {
		if (aniname.value == 'left') return 'round-r-' + props.round
		if (aniname.value == 'right') return 'round-l-' + props.round
		if (aniname.value == 'up') return 'round-b-' + props.round
		if (aniname.value == 'down') return 'round-t-' + props.round
		if (aniname.value == 'zoom') return 'round-' + props.round
	})
	const reverse_rp = computed(() => {
		if (aniname.value != 'zoom') return reverse.value
		return !reverse.value
	})
	const aniname = computed(() => {
		if (props.placement == 'center') return 'zoom'
		if (props.placement == 'top') return 'up'
		if (props.placement == 'bottom') return 'down'
		return props.placement
	})
	const anwidth = computed(() => {
		if (aniname.value == 'zoom') {
			return props.width + props.unit
		}
		if (props.placement == 'left' || props.placement == 'right') {
			return props.width + props.unit
		}
		return sysinfo.width + 'px'
	})
	const anheight = computed(() => {
		let wucha = 0
		if (props.placement == 'top' || props.placement == 'bottom' || aniname.value == 'zoom') {
			return props.height + wucha + props.unit
		}
		return sysinfo.height + 'px'
	})
	const contentHeight = computed(() => {
		let base_height = props.hideHeader ? 0 : 44
		let _footerHeight = uni.$tm.u.topx(props.footHeight)
		if (props.placement == 'top' || props.placement == 'bottom' || aniname.value == 'zoom') {
			let h = props.height
			if (props.unit == 'rpx') {
				h = uni.upx2px(props.height)
			}
			return h - base_height - _footerHeight + 'px'
		}
		return sysinfo.height - base_height - _footerHeight + 'px'
	})
	const align_rp = computed(() => {
		if (aniname.value == 'down') {
			return 'flex-col-bottom-center'
		}
		if (aniname.value == 'up') {
			return 'flex-top-custom'
		}
		if (aniname.value == 'left') {
			return 'flex-row-top-start'
		}
		if (aniname.value == 'right') {
			return 'flex-row-bottom-start'
		}
		if (aniname.value == 'zoom') {
			return 'flex-center'
		}
	})

	async function _beforeOpenFun() {
		if (typeof props.beforeOpen === 'function') {
			loading.value = true
			let p = await props.beforeOpen()
			if (typeof p === 'function') {
				p = await p()
			}
			loading.value = false
		}
	}

	async function _beforeOkFun() {
		let p = true
		if (typeof props.beforeOk === 'function') {
			loading.value = true
			p = await props.beforeOk()
			if (typeof p === 'function') {
				p = await p()
			}
			loading.value = false
			if (!p) return
		}
		return p
	}

	async function _beforeCancelFun() {
		let p = true
		if (typeof props.beforeCance === 'function') {
			loading.value = true
			p = await props.beforeCance()
			if (typeof p === 'function') {
				p = await p()
			}
			loading.value = false
			if (!p) return
		}
		return p
	}

	function OverLayOpen() {
		// nextTick(function() {
		// 	drawerANI.value?.play();
		// })
		_beforeOpenFun()
		_show.value = true
		emits('open')
		emits('update:show', true)
	}
	function overclose() {
		nextTick(() => {
			_show.value = false
			emits('close')
			emits('update:show', false)
		})
	}
	async function overlayClickFun(e : Event) {

		if (!props.overlayClick || props.disabled || !overlayAni.value || loading.value || isPlaying.value) return
		emits('click', e)
		if (!(await _beforeCancelFun())) return
		reverse.value = false
		throttle(
			async () => {
				emits('cancel')
				overlayAni.value?.close()
				drawerANI.value?.play()

			},
			props.duration + 80,
			true
		)
	}
	function playEndEvent() {
		isPlaying.value = false
	}


	async function ok() {
		if (props.disabled || loading.value) return
		if (!(await _beforeOkFun())) return
		reverse.value = false
		debounce(
			() => {
				emits('ok')
				overlayAni.value?.close()
				drawerANI.value?.play()
			},
			500,
			true
		)
	}

	async function cancel() {
		if (props.disabled || loading.value) return
		if (!(await _beforeCancelFun())) return
		reverse.value = false
		debounce(
			() => {
				emits('cancel')
				overlayAni.value?.close()
				drawerANI.value?.play()
			},
			500,
			true
		)
	}

	//外部调用。
	function open() {
		reverse.value = true
		_show.value = true
		nextTick(() => {
			drawerANI.value?.play()
		})
	}

	//外部手动调用关闭方法
	function close() {
		reverse.value = false
		overlayAni.value?.close()
		drawerANI.value?.play()
	}

	//外部调用的方法。
	defineExpose({
		close: close,
		open: open
	})
</script>

<style scoped>
	.flex-left-custom {
		display: flex;
		justify-content: flex-start;
		align-items: flex-start;
	}

	.flex-right-custom {
		display: flex;
		justify-content: flex-start;
		align-items: flex-end;
	}

	.flex-top-custom {
		display: flex;
		justify-content: flex-start;
		align-items: flex-start;
	}

	.flex-end-custom {
		display: flex;
		justify-content: flex-end;
		align-items: flex-end;
	}

	.flex-center-custom {
		display: flex;
		justify-content: center;
		align-items: center;
		flex-direction: row;
	}
</style>